#include "BuildAction.h"
#include "Manager.h"

bool BuildingCompare::operator() (PUnitType& lhs, PUnitType& rhs)
{
	return (lhs.getPriority() <= rhs.getPriority());
}

void BuildAction::_onActionStart()
{
}

void BuildAction::_onActionStop()
{
}

void BuildAction::_onFrame()
{
	if(group == NULL)
		return;
	if(buildQueue->empty())
		stop();
	for ( Unitset::iterator i = group->getUnits()->begin(); i != group->getUnits()->end(); ++i ) {
		// Get a direct pointer to our unit so we do not have to continuously dereference the iterator
		Unit *u = *i;
		if ( u == NULL || !u->exists() )
			continue;

		// Ignore the unit if it has one of the following status ailments
		if ( u->isLockedDown() || u->isMaelstrommed() || u->isStasised() )
			continue;


		// Ignore the unit if it is in one of the following states
		if ( u->isLoaded() || u->isUnpowered() || u->isStuck() )
			continue;

		// Ignore the unit if it is incomplete or busy constructing
		//if ( !u->isCompleted() || u->isConstructing() )
		//	continue;

		// Only Take a unit that is mineing priority of building = max allocatable miners
		if(!u->isGatheringMinerals())
			continue;

		PUnitType bType = buildQueue->top();
		if(bType.getPriority() <= workerCount)
			continue;

		UnitType uType = u->getType();
		int minerals = Broodwar->self()->minerals();
		int gas = Broodwar->self()->gas();

		if(uType.isWorker() && bType.mineralPrice() <= minerals && bType.gasPrice() <= gas) {
			workerCount++;
			Broodwar->printf("Constructing a %s", bType.getName().c_str());
			u->build(bType, bType.getTilePosition());
			// There is no way to get this unit before it exists so
			// and workers cannot set rally points so the unit will
			// not be as acurate because we cannot determine where
			// the unit is from it must be based off the time it takes
			// to build it and the unitType which should be good enough
			// for buildings.
			struct arrival arrival;
			arrival.arrivalTime = bType.buildTime() + Broodwar->getFrameCount();
			arrival.group = bType.getGroup();
			arrival.uType = bType;
			arrival.origin = NULL;
			manager->addArrival(arrival);
			buildQueue->pop();
		}
	}
}

BuildAction::BuildAction() : BasicAction()
{
	buildQueue = new priority_queue<PUnitType, vector<PUnitType>, BuildingCompare>();
	workerCount = 0;
}

BuildAction::~BuildAction()
{
	delete buildQueue;
}

BuildAction* BuildAction::clone()
{
	BuildAction* clone = new BuildAction(*this);
	clone->buildQueue = new priority_queue<PUnitType, vector<PUnitType>, BuildingCompare>(*buildQueue);
	return clone;
}

void BuildAction::addBuildingRequest(PUnitType uType)
{
	buildQueue->push(uType);
}
